﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;
using System.Threading.Tasks;
using System.Linq.Expressions;
using System.Data.Objects.DataClasses;
using JeanFish.Tracing;

namespace JeanFish.Data
{
    /// <summary>
    /// 表示通用实体数据访问。
    /// </summary>
    /// <typeparam name="TDataContext">数据上下文</typeparam>
    /// <typeparam name="TEntity">数据实体类型</typeparam>
    public abstract class CommonDataAccess<TDataContext,TEntity>:CommonDataContext<TDataContext>//,ICommonDataAccess<TEntity>
        where TDataContext : ObjectContext,new()
        where TEntity : EntityObject
    {
        /// <summary>
        /// 实体集
        /// </summary>
        protected virtual IObjectSet<TEntity> EntitySet
        {
            get
            {
                return base.CurrentContext.CreateObjectSet<TEntity>();
            }
        }
        /// <summary>
        /// 实体查询集
        /// </summary>
        protected virtual IQueryable<TEntity> EntityQuery
        {
            get
            {
                return this.EntitySet.AsQueryable();
            }
        }
        /// <summary>
        /// 读取实体数据
        /// </summary>
        /// <param name="whereClause">条件查询语句</param>
        /// <param name="detached">是否与数据集分离</param>
        /// <param name="defaultEntity">未得到实体时返回的默认值</param>
        /// <returns>实体数据，空则null</returns>
        protected TEntity Read(Expression<Func<TEntity, bool>> whereClause,bool detached=false, TEntity defaultEntity = null)
        {
            var result = this.EntityQuery.FirstOrDefault(whereClause);
            if (detached&&result != null)
                EntitySet.Detach(result);
            if (result == null)
                result = defaultEntity;
            return result;
        }
        /// <summary>
        /// 获取满足条件的实体数目。
        /// </summary>
        /// <param name="whereClause">查询条件</param>
        /// <returns>结果</returns>
        protected int Count(Expression<Func<TEntity, bool>> whereClause)
        {
            return this.EntityQuery.Count(whereClause);
        }
        /// <summary>
        /// 判断指定条件的数据是否存在。
        /// </summary>
        /// <param name="whereClause">查询条件</param>
        /// <returns>结果</returns>
        protected bool Exist(Expression<Func<TEntity, bool>> whereClause)
        {
            return this.EntityQuery.Any(whereClause);
        }
        /// <summary>
        /// 创建实体
        /// </summary>
        /// <param name="entity">要创建的实体</param>
        /// <returns>影响实体数</returns>
        protected int Create(TEntity entity)
        {
            this.EntitySet.AddObject(entity);
            try
            {
                return this.CurrentContext.SaveChanges();
            }
            catch (OptimisticConcurrencyException)
            {
                this.CurrentContext.Refresh(RefreshMode.ClientWins, entity);
                return this.CurrentContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
            }
            finally
            {
                if (entity.EntityState != EntityState.Added)
                {
                    this.CurrentContext.AcceptAllChanges();
                    this.CurrentContext.Refresh(RefreshMode.StoreWins, entity);
                }
            }
        }
        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity">要更新的实体</param>
        /// <returns>影响实体数</returns>
        protected int Update(TEntity entity)
        {
            try
            {
                if(entity.EntityState==EntityState.Detached)
                    EntitySet.Attach(entity);
                this.CurrentContext.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
                return this.CurrentContext.SaveChanges();
            }
            catch (OptimisticConcurrencyException)
            {
                this.CurrentContext.Refresh(RefreshMode.ClientWins, entity);
                return this.CurrentContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
            }
            finally
            {
                if (entity.EntityState != EntityState.Modified)
                {
                    this.CurrentContext.AcceptAllChanges();
                    this.CurrentContext.Refresh(RefreshMode.StoreWins, entity);
                }
            }
        }
        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">要删除的实体</param>
        /// <returns>影响实体数</returns>
        protected int Delete(TEntity entity)
        {
            this.EntitySet.DeleteObject(entity);
            try
            {
                return this.CurrentContext.SaveChanges();
            }
            catch(Exception ex)
            {
                ex.WriteLog(0, System.Diagnostics.TraceEventType.Error);
                this.CurrentContext.Refresh(RefreshMode.ClientWins, entity);
                return this.CurrentContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
            }
            finally
            {
                if (entity != null && entity.EntityState != EntityState.Deleted)
                {
                    this.CurrentContext.AcceptAllChanges();
                    this.CurrentContext.Refresh(RefreshMode.StoreWins, this.EntitySet);
                }
            }
        }
        /// <summary>
        /// 列出实体
        /// </summary>
        /// <param name="whereClause">条件查询语句，null表示不筛选</param>
        /// <param name="orderbyClause">排序语句，null表示不排序</param>
        /// <param name="ascend">升序/降序，不排序时无效</param>
        /// <param name="pageSize">分页规模，0表示不分页</param>
        /// <param name="pageIndex">开始页，不分页时无效</param>
        /// <param name="total">返回实体总数</param>
        /// <returns>实体列表</returns>
        protected IQueryable<TEntity> List(Expression<Func<TEntity, bool>> whereClause, Expression<Func<TEntity, object>> orderbyClause, bool ascend, int pageSize, int pageIndex, out int total)
        {
            IQueryable<TEntity> result = EntityQuery;
            if (whereClause != null)
                result = result.Where(whereClause);
            total = result.Count();
            if (orderbyClause != null)
            {
                result = ascend ? result.OrderBy(orderbyClause) : result.OrderByDescending(orderbyClause);
            }
            if (pageSize > 0)
            {
                result = result.Skip(pageSize * pageIndex).Take(pageSize);
            }
            return result;
        }
    }
}
